<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- 
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License. 
-->
<html>
<head>
    <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css">
    <style type="text/css">
        .dp-highlighter {
            width:95% !important;
        }
    </style>
    <style type="text/css">
        .footer {
            background-image:      url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif');
            background-repeat:     repeat-x;
            background-position:   left top;
            padding-top:           4px;
            color:                 #666;
        }
    </style>
    <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' />
    <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' />
    <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script>
    <script type="text/javascript">
        SyntaxHighlighter.defaults['toolbar'] = false;
        SyntaxHighlighter.all();
    </script>
    <script type="text/javascript" language="javascript">
        var hide = null;
        var show = null;
        var children = null;

        function init() {
            /* Search form initialization */
            var form = document.forms['search'];
            if (form != null) {
                form.elements['domains'].value = location.hostname;
                form.elements['sitesearch'].value = location.hostname;
            }

            /* Children initialization */
            hide = document.getElementById('hide');
            show = document.getElementById('show');
            children = document.all != null ?
                    document.all['children'] :
                    document.getElementById('children');
            if (children != null) {
                children.style.display = 'none';
                show.style.display = 'inline';
                hide.style.display = 'none';
            }
        }

        function showChildren() {
            children.style.display = 'block';
            show.style.display = 'none';
            hide.style.display = 'inline';
        }

        function hideChildren() {
            children.style.display = 'none';
            show.style.display = 'inline';
            hide.style.display = 'none';
        }
    </script>
    <title>S2-015</title>
</head>
<body onload="init()">
<table border="0" cellpadding="2" cellspacing="0" width="100%">
    <tr class="topBar">
        <td align="left" valign="middle" class="topBarDiv" align="left" nowrap>
            &nbsp;<a href="home.html">Home</a>&nbsp;&gt;&nbsp;<a href="security-bulletins.html">Security Bulletins</a>&nbsp;&gt;&nbsp;<a href="s2-015.html">S2-015</a>
        </td>
        <td align="right" valign="middle" nowrap>
            <form name="search" action="https://www.google.com/search" method="get">
                <input type="hidden" name="ie" value="UTF-8" />
                <input type="hidden" name="oe" value="UTF-8" />
                <input type="hidden" name="domains" value="" />
                <input type="hidden" name="sitesearch" value="" />
                <input type="text" name="q" maxlength="255" value="" />
                <input type="submit" name="btnG" value="Google Search" />
            </form>
        </td>
    </tr>
</table>

<div id="PageContent">
    <div class="pageheader" style="padding: 6px 0px 0px 0px;">
        <!-- We'll enable this once we figure out how to access (and save) the logo resource -->
        <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"-->
        <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div>
        <div style="margin: 0px 10px 8px 10px"  class="pagetitle">S2-015</div>

        <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;">
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=31823638">
                <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=31823638">Edit Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">
                <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a>
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=31823638">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=31823638">Add Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=31823638">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add News"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=31823638">Add News</a>
        </div>
    </div>

    <div class="pagecontent">
        <div class="wiki-content">
            <div id="ConfluenceContent"><h2 id="S2-015-Summary">Summary</h2>

<p>
</p><p>A vulnerability introduced by wildcard matching mechanism or double evaluation of OGNL Expression allows remote command execution.</p>

<div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Who should read this</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>All Struts 2 developers and users</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Impact of vulnerability</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>Remote command execution, remote server context manipulation, injection of malicious client side code</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Maximum security rating</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>Highly Critical</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Recommendation</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>Developers should immediately upgrade to <a shape="rect" class="external-link" href="http://struts.apache.org/download.cgi#struts23143">Struts 2.3.14.3</a></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Affected Software</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p> Struts 2.0.0 - Struts 2.3.14.2 </p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Reporter</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p> Jon Passki from Coverity Security Research Laboratory reported directly to security@struts.a.o and via <a shape="rect" class="external-link" href="https://communities.coverity.com/blogs/security/2013/05/29/struts2-remote-code-execution-via-ognl-injection" rel="nofollow">blog post</a> </p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>CVE Identifier</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p><a shape="rect" class="external-link" href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-2135" rel="nofollow">CVE-2013-2135</a>, <a shape="rect" class="external-link" href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-2134" rel="nofollow">CVE-2013-2134</a></p></td></tr></tbody></table></div>


<h2 id="S2-015-Problem">Problem</h2>

<p>Struts 2 allows define action mapping base on wildcards, like in example below:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">
&lt;action name="*" class="example.ExampleSupport"&gt;
    &lt;result&gt;/example/{1}.jsp&lt;/result&gt;
&lt;/action&gt;
</pre>
</div></div>

<p>If a request doesn't match any other defined action, it will be matched by <code>*</code> and requested action name will be used to load JSP file base on the name of action. And as value of {<code>1</code>} is threaten as an OGNL expression, thus allow to execute arbitrary Java code on server side. This vulnerability is combination of two problems:</p>
<ul class="alternate"><li>requested action name isn't escaped or checked agains whitelist</li><li>double evaluation of an OGNL expression in <code>TextParseUtil.translateVariables</code> when combination of <code>$</code> and <code>%</code> open chars is used.</li></ul>


<h2 id="S2-015-Proofofconcept">Proof of concept</h2>

<h4 id="S2-015-Wildcardmatching">Wildcard matching</h4>
<ol><li>Run struts2-blank app</li><li>Open the following url, resulting in dynamic action name resolution based on passed value of <code>#foo</code>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">http://localhost:8080/example/%24%7B%23foo%3D%27Menu%27%2C%23foo%7D</pre>
</div></div>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">http://localhost:8080/example/${#foo='Menu',#foo}</pre>
</div></div></li></ol>


<p>As you can notice, action name is resolved based on user input and you can put any arbitrary code to perform attack.</p>

<h4 id="S2-015-Doubleevaluationofanexpression">Double evaluation of an expression</h4>
<ol><li>Open example.xml present in the Struts Blank App and change result of HelloWorld action to one below:
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">
&lt;result type="httpheader"&gt;
    &lt;param name="headers.foobar"&gt;${message}&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div></li><li>Open HelloWorld.java and change <code>execute()</code> method as below:
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">
public String execute() throws Exception {
    return SUCCESS;
}
</pre>
</div></div></li><li>Run struts2-blank app</li><li>Open the following url (you must have a tool to check response headers)
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">http://localhost:8080/example/HelloWorld.action?message=%24{%25{1%2B2}}</pre>
</div></div>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">http://localhost:8080/example/HelloWorld.action?message=${%{1+2}}</pre>
</div></div></li><li>Check value of <code>foobar</code> header, it should be <code>3</code></li></ol>


<p>As you can notice, passed value of <code>message</code> parameter was used to set value of <code>foobar</code> header and the value was double evaluated - first time when <code>${message</code>} was evaluated, secondly when parsed value (<code>${%{1+2</code>}}) was evaluated again.</p>

<h2 id="S2-015-Solution">Solution</h2>

<p>With the new version actions' names whitelisting was introduced and by default is set to accept actions that match the following regex:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">[a-z]*[A-Z]*[0-9]*[.\-_!/]*</pre>
</div></div>
<p>user can change the definition by setting up a new constant in struts.xml as below:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">
&lt;constant name="struts.allowed.action.names" value="[a-zA-Z]*" /&gt;
</pre>
</div></div>

<p>Double evaluation of passed expression was removed from <code>OgnlTextParser</code> which is used by <code>TextParseUtil.translateVariables</code>.</p>

<div class="confluence-information-macro confluence-information-macro-note"><p class="title">Backward Compatibility</p><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body">
<p>There should be no problems with migration from previous version.</p></div></div>

<div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body">
<p><strong>It is strongly recommended to upgrade to <a shape="rect" class="external-link" href="http://struts.apache.org/download.cgi#struts23143">Struts 2.3.14.3</a>.</strong></p></div></div></div>
        </div>

        
    </div>
</div>
<div class="footer">
    Generated by CXF SiteExporter
</div>
</body>
</html>
